package com.feature50.makeover;

import com.feature50.makeover.filthy.GraphicsUtilities;
import com.feature50.makeover.filthy.ShadowRenderer;
import com.feature50.makeover.utils.FontResolver;
import com.feature50.makeover.utils.ImageUtils;

import javax.swing.*;
import javax.swing.tree.TreeModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

public class NavigationPanel extends JPanel {
    static final BufferedImage STAR_NORMAL = ImageUtils.getImage("star_white.png");
    static final BufferedImage STAR_SELECTED = ImageUtils.getImage("star_black.png");
    static final BufferedImage STAR_MARKED = ImageUtils.getImage("star_orange.png");

    static final FontResolver.FontInfo[] FONT_NAV_DEFAULT = new FontResolver.FontInfo[] {
            new FontResolver.FontInfo("Franklin Gothic Medium", 11)
    };

    static final FontResolver.FontInfo[] FONT_NAV_HEADER = new FontResolver.FontInfo[] {
            new FontResolver.FontInfo("Franklin Gothic Medium", 12)
    };

    private NavigationTopPanel topPanel;
    private NavigationBottomPanel bottomPanel;

    private BufferedImage topImage;
    private BufferedImage bottomImage;
    private BufferedImage topImageShadow;
    private BufferedImage bottomImageShadow;

    private BufferedImage navShadow;
    private Dimension navShadowSourceSize;

    private float top = .6f;

    private float built = 0f;

    private ShadowRenderer shadow = new ShadowRenderer();

    public NavigationPanel(final DesktopFrame frame) {
        setLayout(null);

        topPanel = new NavigationTopPanel(frame, this);
        topPanel.setBackground(Color.RED);
        add(topPanel);
        bottomPanel = new NavigationBottomPanel(frame, this);
        bottomPanel.setBackground(Color.BLUE);
        add(bottomPanel);

        getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "esc-action");
        getActionMap().put("esc-action", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                frame.hideNavigation();
            }
        });
    }

    public void resetImages() {
        topImage = null;
        bottomImage = null;
        topImageShadow = null;
        bottomImageShadow = null;
    }

    protected void paintChildren(Graphics g) {
        if (built != 1f) return;

        // avoid storing the images in memory after they are no longer necessary
        resetImages();

        BufferedImage img = GraphicsUtilities.createCompatibleImage(getWidth() - shadow.getSize(), getHeight());
        Graphics2D g2d = img.createGraphics();
        super.paintChildren(g2d);
        g2d.dispose();

        if ((navShadow == null) || (navShadowSourceSize.equals(new Dimension(img.getWidth(), img.getHeight())))) {
            navShadow = shadow.createShadow(img);
            navShadowSourceSize = new Dimension(img.getWidth(), img.getHeight());
        }
        g.drawImage(navShadow, 0, 0, null);
        g.drawImage(img, 0, 0, null);
    }

    public void doLayout() {
        int height = getHeight();
        int topHeight = (int) (height * top);
        int bottomHeight = height - topHeight;

        int width = getWidth() - shadow.getSize();

        topPanel.setBounds(0, 0, width, topHeight);
        bottomPanel.setBounds(0, topHeight, width, bottomHeight);
    }

    private int getTopPanelY(int topPanelHeight) {
        return (int) -((1f - built) * topPanelHeight);
    }

    private int getBottomPanelY(int topPanelHeight) {
        int rangeBottom = getHeight() - topPanelHeight;
        return (int) (topPanelHeight + ((1f - built) * rangeBottom));
    }

    protected void paintComponent(Graphics g) {
        if (built == 1f) return;
        if (built == 0f) return;

        if ((topImage == null) || (topImage.getHeight() != topPanel.getHeight())) {
            topImage = GraphicsUtilities.createCompatibleImage(topPanel.getWidth(), topPanel.getHeight());
            Graphics2D g2d = topImage.createGraphics();
            topPanel.print(g2d);
            g2d.dispose();

            topImageShadow = shadow.createShadow(topImage);

            bottomImage = GraphicsUtilities.createCompatibleImage(bottomPanel.getWidth(), bottomPanel.getHeight());
            g2d = bottomImage.createGraphics();
            bottomPanel.print(g2d);
            g2d.dispose();

            bottomImageShadow = shadow.createShadow(bottomImage);
        }

        int topY = getTopPanelY(topImage.getHeight());
        int bottomY = getBottomPanelY(topImage.getHeight());

        g.drawImage(topImageShadow, 0, topY, null);
        g.drawImage(topImage, 0, topY, null);

        g.drawImage(bottomImageShadow, 0, bottomY, null);
        g.drawImage(bottomImage, 0, bottomY, null);
    }

    public float getBuilt() {
        return built;
    }

    public void setBuilt(float built) {
        this.built = built;
    }

    public void setFocusToQuickFind() {
        topPanel.getText().requestFocus();
    }

    public void setTreeModel(TreeModel model) {
        topPanel.setTreeModel(model);
    }

    public void addRecentApp(ENode node) {
        bottomPanel.addRecentApp(node);
    }

    public void addFavorite(ENode app) {
        bottomPanel.getFavoritesModel().addFavorite(app);
        topPanel.getTree().repaint();
    }

    public void removeFavorite(ENode app) {
        bottomPanel.getFavoritesModel().removeFavorite(app);
        topPanel.getTree().repaint();
    }

    public boolean isFavorite(ENode app) {
        return bottomPanel.getFavoritesModel().isFavorite(app);
    }
}
